#pragma once
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <queue>

int default_num = 5;

template <class T>
class BlockQueue
{
public:
    //BlockQueue(){}

    bool IsFull() { return _q.size() == _capacity; }

    bool IsEmpty() { return _q.empty(); }

    BlockQueue(int size = default_num)
        :_capacity(size),
        _Csleep_num(0),
        _Psleep_num(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_Full,nullptr);
        pthread_cond_init(&_Empty,nullptr);
    }

    void Equeue(const T& in)
    {
        pthread_mutex_lock(&_mutex);

        while(IsFull())
        {
            _Psleep_num++;
            std::cout << "生产者休眠了" << std::endl;
            pthread_cond_wait(&_Full,&_mutex);
            _Psleep_num--;
        }   
        _q.push(in);
        std::cout << "生产者进行生产" << std::endl;
        sleep(1);

        if(_Csleep_num > 0)
        {
            pthread_cond_signal(&_Empty);
        }
        pthread_mutex_unlock(&_mutex);   
    }

    T Pop()
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            _Csleep_num++;
            std::cout << "消费者休眠了" << std::endl;
            pthread_cond_wait(&_Empty,&_mutex);
            _Csleep_num--;

        }
        T data = _q.front();
        _q.pop();
        sleep(1);

        if(_Psleep_num > 0)
        {
            pthread_cond_signal(&_Full);
        }
        pthread_mutex_unlock(&_mutex);
        return data;
    }


    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_Full);
        pthread_cond_destroy(&_Empty);
    }

private:
    std::queue<T> _q;
    int _capacity;

    pthread_mutex_t _mutex;
    pthread_cond_t _Full;
    pthread_cond_t _Empty;

    int _Csleep_num;
    int _Psleep_num;
};